#include "Renderer.h"
#include "Basic/FileSystem.h"
#include "Windows/GxWinApp.h"
#include "RenderUtils.h"
#include "float.h"

using namespace GxWinGUI;

namespace FinalRendering
{
	namespace Engine
	{
		const int BrightnessEvalRectSize = 32;
		const int BrightnessEvalLevel = 5;
		HDR_Processor::HDR_Processor(int w, int h)
		{
			lastBrightness = brightness = 0.6f;
			width = w;
			height = h;

			AutoExposureRate = 0.2f;

			colorHDR = new Lightmap(w, h);
			rbColor = new RenderBuffer(GL_DEPTH_COMPONENT, w, h);
			fboHDR = new FrameBufferObject();
			fboHDR->AttachTexture(GL_COLOR_ATTACHMENT0, colorHDR->GetHandle());
			fboHDR->AttachRenderBuffer(GL_DEPTH_ATTACHMENT, rbColor.operator ->());

			bloom = new Lightmap(w,h, true);
			fboBloom = new FrameBufferObject();
			fboBloom->AttachTexture(GL_COLOR_ATTACHMENT0, bloom->GetHandle());

			brightnessEval = new Lightmap(BrightnessEvalRectSize,BrightnessEvalRectSize);
			fboBrightness = new FrameBufferObject();
			fboBrightness->AttachTexture(GL_COLOR_ATTACHMENT0, brightnessEval->GetHandle());

			colorHalf = new Lightmap(w/2,h/2, true);
			fboHalf = new FrameBufferObject();
			fboHalf->AttachTexture(GL_COLOR_ATTACHMENT0, colorHalf->GetHandle());

			colorQuad = new Lightmap(w/4,h/4, true);
			fboQuad = new FrameBufferObject();
			fboQuad->AttachTexture(GL_COLOR_ATTACHMENT0, colorQuad->GetHandle());

			colorOct = new Lightmap(w/8,h/8, true);
			fboOct = new FrameBufferObject();
			fboOct->AttachTexture(GL_COLOR_ATTACHMENT0, colorOct->GetHandle());


			bloomBlur = new Lightmap(w/8, h/8, true);
			fboBlur = new FrameBufferObject();
			fboBlur->AttachTexture(GL_COLOR_ATTACHMENT0, bloomBlur->GetHandle());

			progBloom = new Program(L"Shaders/Bloom.gxprog");
			locBloomSrc = progBloom->GetUniformLocation(L"src");
			locBloomBrightness = progBloom->GetUniformLocation(L"brightness");

			progTone = new Program(L"Shaders/Tone.gxprog");
			locToneSrc = progTone->GetUniformLocation(L"src");
			locToneBrightness = progTone->GetUniformLocation(L"exposure");
			locToneBloom = progTone->GetUniformLocation(L"bloom");

			progDownSample = new Program(L"Shaders/DownSample.gxprog");
			locDSSrc = progDownSample->GetUniformLocation(L"src");
			locDSdx = progDownSample->GetUniformLocation(L"dx");
			locDSdy = progDownSample->GetUniformLocation(L"dy");

			progBlurX = new Program(L"Shaders/GuassianBlurX.gxprog");
			locBlurXSrc = progBlurX->GetUniformLocation(L"src");
			locBlurXD = progBlurX->GetUniformLocation(L"d");

			progBlurY = new Program(L"Shaders/GuassianBlurY.gxprog");
			locBlurYSrc = progBlurY->GetUniformLocation(L"src");
			locBlurYD = progBlurY->GetUniformLocation(L"d");
		}

		void HDR_Processor::BeginRendering()
		{
			bool ready = fboHDR->IsReady();
			fboHDR->Bind();
		}

		float HDR_Processor::EvalBrightness(int id)
		{
			float pix[4] = {-1.0f, -1.0f, -1.0f, -1.0f};
			Shader::UseProgramObjectARB(0);
			MultiTexture::ActiveTexture(GL_TEXTURE0);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, id);
			//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			//OpenGL::GenerateMipmap(GL_TEXTURE_2D);
			//glBindTexture(GL_TEXTURE_2D, id);
			//OpenGL::GenerateMipmap(GL_TEXTURE_2D);
			//
			//
			//int err = glGetError();
			////glEnable(GL_TEXTURE_2D);
			//
			//glGetTexImage(GL_TEXTURE_2D, BrightnessEvalLevel, GL_RGBA, GL_FLOAT, pix);
			//err = glGetError();
			//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			//

			float brightness;

			//brightness = max(pix[0], max(pix[1], pix[2]));

			//if (brightness < 0.0f || _isnan(brightness) || !_finite(brightness))
			{
				int count = 0;
				brightness = 0.0f;
				pixBuf.SetSize(BrightnessEvalRectSize * BrightnessEvalRectSize * 4);
				glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixBuf.Buffer());
				float * pix = pixBuf.Buffer();
				for (int i=0; i<BrightnessEvalRectSize * BrightnessEvalRectSize; i++)
				{
					float lum = max(pix[i*4], max(pix[i*4+1], pix[i*4+2]));
					if (!_isnan(lum) && _finite(lum))
					{
						brightness += lum;
						count ++;
					}
				}
				if (count)
					brightness /= count;
				else
					brightness = 1.0f;
			}

			//brightness *= 2.4f;

			if (brightness < 0.4f)
				brightness = 0.4f;
			if (brightness > 8.0f)
				brightness = 8.0f;

			if (_isnan(brightness) || !_finite(brightness))
			{
				brightness = 1.0f;
			}

			return brightness;
		}

		void DrawFrame(int width, int height, float mx =0.0f, float my=0.0f)
		{
			SetupView(width, height, (float)width, (float)height);
			glDisable(GL_DEPTH_TEST);
			glBegin(GL_QUADS);
				glTexCoord2f(mx,1.0f-my);
				glVertex2i(0,0);
				glTexCoord2f(mx,my);
				glVertex2i(0,height);
				glTexCoord2f(1.0f-mx,my);
				glVertex2i(width,height);
				glTexCoord2f(1.0f-mx,1.0f-my);
				glVertex2i(width,0);
			glEnd();
			glEnable(GL_DEPTH_TEST);
			ResetView();
		}

		void HDR_Processor::DownSample()
		{
			float dx = 1.0f/width;
			float dy = 1.0f/height;
			progDownSample->Bind();
			progDownSample->SetUniform(locDSSrc, 0);
			progDownSample->SetUniform(locDSdx, dx);
			progDownSample->SetUniform(locDSdy, dy);

			fboHalf->Bind();
			glBindTexture(GL_TEXTURE_2D, bloom->GetHandle());
			DrawFrame(width/2, height/2, 0.5f*dx, 0.5f*dy);
			fboHalf->UnBind();

			progDownSample->SetUniform(locDSdx, 2.0f*dx);
			progDownSample->SetUniform(locDSdy, 2.0f*dy);

			fboQuad->Bind();
			glBindTexture(GL_TEXTURE_2D, colorHalf->GetHandle());
			DrawFrame(width/4, height/4, dx, dy);
			fboQuad->UnBind();

			progDownSample->SetUniform(locDSdx, 4.0f*dx);
			progDownSample->SetUniform(locDSdy, 4.0f*dy);

			fboOct->Bind();
			glBindTexture(GL_TEXTURE_2D, colorQuad->GetHandle());
			DrawFrame(width/8, height/8, 2.0f*dx, 2.0f*dy);
			fboOct->UnBind();
			
			progDownSample->UnBind();
		}

		void HDR_Processor::Blur()
		{
			progBlurX->Bind();
			progBlurX->SetUniform(locBlurXSrc, 0);
			progBlurX->SetUniform(locBlurXD, 8.0f/width);

			MultiTexture::ActiveTexture(GL_TEXTURE0);

			fboBlur->Bind();
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, colorOct->GetHandle());
			DrawFrame(width/8, height/8/*, 4.0f/width, 4.0f/height*/);
			fboBlur->UnBind();

			progBlurX->UnBind();


			progBlurY->Bind();
			progBlurY->SetUniform(locBlurYSrc, 0);
			progBlurY->SetUniform(locBlurYD, 8.0f/height);
			
			fboOct->Bind();
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, bloomBlur->GetHandle());
			DrawFrame(width/8, height/8);
			fboOct->UnBind();

			progBlurY->UnBind();
	
		}

		void HDR_Processor::EndRendering(float dTime)
		{
			glDepthMask(GL_FALSE);
			fboHDR->UnBind();
			
			Shader::UseProgramObjectARB(0);

			int w = brightnessEval->GetWidth();
			int h = brightnessEval->GetHeight();
			SetupView(w, h, (float)w, (float)h);
			glDisable(GL_DEPTH_TEST);
			MultiTexture::ActiveTexture(GL_TEXTURE0);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, brightnessEval->GetHandle());
			glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
			OpenGL::GenerateMipmap(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, colorHDR->GetHandle());
			glColor4ub(255,255,255,255);
			Shader::UseProgramObjectARB(0);
			const float Margin = 0.2f;
			const float InvMargin = 1.0f - Margin;
			bool ready = fboBrightness->IsReady();
			
			fboBrightness->Bind();
			glClear(GL_COLOR_BUFFER_BIT);
			glBegin(GL_QUADS);
				glTexCoord2f(Margin,Margin);
				glVertex2i(0,0);
				glTexCoord2f(Margin,InvMargin);
				glVertex2i(0,h);
				glTexCoord2f(InvMargin,InvMargin);
				glVertex2i(w,h);
				glTexCoord2f(InvMargin,Margin);
				glVertex2i(w,0);
			glEnd();
			fboBrightness->UnBind();
			glDisable(GL_TEXTURE_2D);
			glEnable(GL_DEPTH_TEST);
			ResetView();
			
			brightness = EvalBrightness(brightnessEval->GetHandle());
			
			brightness = lastBrightness + (brightness - lastBrightness) * ( 1 - pow( 0.98f, 30 * dTime ) );
			lastBrightness = brightness;

			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, colorHDR->GetHandle());

			progBloom->Bind();
			progBloom->SetUniform(locBloomSrc, 0);
			progBloom->SetUniform(locBloomBrightness, brightness);
			fboBloom->Bind();
			DrawFrame(colorHDR->GetWidth(), colorHDR->GetHeight());
			fboBloom->UnBind();
			progBloom->UnBind();
			
			DownSample();

			for (int i=0; i<4; i++)
			{
				Blur();
				Blur();
				Blur();
				Blur();
			}

			progTone->Bind();
			progTone->SetUniform(locToneSrc, 0);
			progTone->SetUniform(locToneBrightness, brightness);
			progTone->SetUniform(locToneBloom, 1);
			
			MultiTexture::ActiveTexture(GL_TEXTURE0);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, colorHDR->GetHandle());
			MultiTexture::ActiveTexture(GL_TEXTURE1);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, colorOct->GetHandle());
			
			DrawFrame(colorHDR->GetWidth(), colorHDR->GetHeight());
			
			glDisable(GL_TEXTURE_2D);
			MultiTexture::ActiveTexture(GL_TEXTURE0);
			progTone->UnBind();

			glDepthMask(GL_TRUE);
		}

		Renderer::Renderer(int w, int h)
			:width(w), height(h), camera(0)
		{
			programPool = new ProgramPool();
			MaterialFile matFile(L"Materials/General.gmt");
			generalMaterial = new Material(matFile, programPool.operator ->());
			WireFrame = false;
			PvsCulling = true;
			SetResolution(w, h);
			VBO::GenBuffers(1, &vbo);
		}

		Renderer::~Renderer()
		{
			VBO::DeleteBuffers(1, &vbo);
		}

		void Renderer::SetCamera(GxRendering::Camera * cam)
		{
			camera = cam;
		}

		void Renderer::SetResolution(int w, int h)
		{
			hdr = new HDR_Processor(w, h);
			width = w;
			height = h;
			reflectionRenderBuffer = new RenderBuffer(GL_DEPTH_COMPONENT, w, h);
			for (int i=0; i<MaxReflectionLevel; i++)
			{
				reflectionFrameBuffers[i] = new FrameBufferObject();
				reflectionFrameBuffers[i]->AttachRenderBuffer(GL_DEPTH_ATTACHMENT, reflectionRenderBuffer.operator->());
				reflectionTextures[i] = new Lightmap(w,h,true);
				reflectionFrameBuffers[i]->AttachTexture(GL_COLOR_ATTACHMENT0, reflectionTextures[i]->GetHandle());
				if (!reflectionFrameBuffers[i]->IsReady())
					throw Exception(L"Unable to setup reflection frame buffers.");
			}
		}

		void Renderer::SetNode(int node_id)
		{
			nodeID = node_id;
		}

		void Renderer::DebugDrawLightmap(int id)
		{
			glDisable(GL_BLEND);
			glBindTexture(GL_TEXTURE_2D, solution->GetLightmap(id,1)->GetHandle());
			glColor4ub(255,255,255,255);
			glBegin(GL_QUADS);
				glTexCoord2i(0,0);
				glVertex2i(0,0);
				glTexCoord2i(0,1);
				glVertex2i(0,512);
				glTexCoord2i(1,1);
				glVertex2i(512,512);
				glTexCoord2i(1,0);
				glVertex2i(512,0);
			glEnd();
		}

		Material * Renderer::GetMaterial(int id)
		{
			if (id >= 0 && id < materials.Count())
				return materials[id].operator->();
			return 0;
		}

		void Renderer::SetScene(Scene *_scene)
		{
			scene = _scene;
			materials.Clear();
			for (int i=0; i<scene->MatNames.Count(); i++)
			{
				MaterialFile file;
				String mName = String(L"Materials/")+scene->MatNames[i];
				if (scene->MatNames[i].GetLength() && FileExists(mName))
					file.Load(String(L"Materials/")+scene->MatNames[i]);
				else
					file.Load(L"Materials/General.gmt");
				Material * mat = new Material(file, programPool.operator ->());
				mat->OnSetClientUniform.Bind(this, &Renderer::Material_OnSetClientUniform);
				materials.Add(mat);
			}

			VBO::BindBuffer(GL_ARRAY_BUFFER, vbo);
			VBO::BufferData(GL_ARRAY_BUFFER, scene->Vertices.Count()*sizeof(Vertex), scene->Vertices.Buffer(), GL_STATIC_DRAW);
			VBO::BindBuffer(GL_ARRAY_BUFFER, 0);
			//scene->Vertices.Clear();
			//scene->Vertices.Compress();
		}

		void Renderer::LoadLightmapSolution(LightmapSolution * _solution)
		{
			solution = _solution;
		}

		void Renderer::Material_OnSetClientUniform(Material * mat, Object * target, const String & uniName, int loc)
		{
			Surface * surf = (Surface *)target;
			if (uniName == L"lightmap1")
				Shader::Uniform1iARB(loc, 3);
			else if (uniName == L"lightmap2")
				Shader::Uniform1iARB(loc, 4);
			else if (uniName == L"lightmap3")
				Shader::Uniform1iARB(loc, 5);
			/*else if (uniName == L"reflectTexture")
				Shader::Uniform1iARB(loc, 7);*/
			else if (uniName == L"screenWidth")
				Shader::Uniform1iARB(loc, width);
			else if (uniName == L"screenHeight")
				Shader::Uniform1iARB(loc, height);
		}

		bool SurfaceRenderCommand::operator == (const SurfaceRenderCommand & cmd)
		{
			return mat == cmd.mat && surf->LightmapID == cmd.surf->LightmapID;
		}
		bool SurfaceRenderCommand::operator < (const SurfaceRenderCommand & cmd)
		{
			Program * p1 = mat->GetProgram();
			Program * p2 = cmd.mat->GetProgram();
			if (p1 < p2)
				return true;
			else if (p1 == p2)
			{
				if (surf->LightmapID < cmd.surf->LightmapID)
					return true;
				else if (surf->LightmapID == cmd.surf->LightmapID)
				{
					if (mat < cmd.mat)
						return true;
					else
						return false;
				}
				else
					return false;
			}
			else
				return false;
		}

		void Renderer::Render(float dTime)
		{
			//glLineStipple(1, 0xFFFF);
			
			if (camera)
				camera->Transform();

			OpenGL::ClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
			OpenGL::ClampColor(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
			OpenGL::ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);

			if (WireFrame)
				glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
			else
			{
				glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
				hdr->BeginRendering();
				glClearColor(1.0f,0.0f,0.0f,1.0f);
				glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			}
			
			renderQueue.Clear();
			for (int i=0; i<scene->BSP.Count(); i++)
			{
				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				if (scene->BSP[i].IsLeaf())
				{
					if (PvsCulling && !scene->PVS->Get(scene->BSP[i].PVS_ID, scene->BSP[nodeID].PVS_ID))
						continue;
					for (int j=0; j<scene->BSP[i].SurfaceCount; j++)
					{
						SurfaceRenderCommand cmd;
						cmd.surf = &(scene->BSP[i].Surfaces[j]);
						cmd.mat = materials[cmd.surf->MatID].operator ->();
						renderQueue.Add(cmd);
					}
				}
			}

			renderQueue.Sort();

			VBO::BindBuffer(GL_ARRAY_BUFFER, vbo);
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(3, GL_FLOAT, 40, 0);
			MultiTexture::ClientActiveTexture(GL_TEXTURE0);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glTexCoordPointer(2, GL_FLOAT, 40, (void *)24);
			MultiTexture::ClientActiveTexture(GL_TEXTURE1);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glTexCoordPointer(2, GL_FLOAT, 40, (void *)32);
			MultiTexture::ClientActiveTexture(GL_TEXTURE0);
			glEnable(GL_CULL_FACE);
			glDisable(GL_BLEND);

			DrawQueue();
		
			solution->UnBindLightmap();
			MultiTexture::ActiveTexture(GL_TEXTURE3);
			glDisable(GL_TEXTURE_2D);
			MultiTexture::ActiveTexture(GL_TEXTURE2);
			glDisable(GL_TEXTURE_2D);
			MultiTexture::ActiveTexture(GL_TEXTURE1);
			glDisable(GL_TEXTURE_2D);
			MultiTexture::ActiveTexture(GL_TEXTURE0);

			MultiTexture::ClientActiveTexture(GL_TEXTURE1);
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
			MultiTexture::ClientActiveTexture(GL_TEXTURE0);
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);

			glDisableClientState(GL_VERTEX_ARRAY);
			VBO::BindBuffer(GL_ARRAY_BUFFER,0);

			if (!WireFrame)
				hdr->EndRendering(dTime);

		}

		void Renderer::DrawQueue(int recurseLevel)
		{
			int curLightmapID = -1;
			Material * curMat = 0;
			for (int i=0; i<renderQueue.Count(); i++)
			{
				Material *&mat = renderQueue[i].mat;
				Surface *& surf = renderQueue[i].surf;
				if (WireFrame)
				{
					Shader::UseProgramObjectARB(0);
					glColor4ub(50,255,20,255);
				}
				else
				{
					if (mat->GetProgram()->IsReflective())
					{
						Plane plane;
						memcpy(&plane, &scene->Vertices[surf->Vertices[0]].Normal, sizeof(float)*3);
						if (recurseLevel<MaxReflectionLevel )
						{
							Matrix4 mtrans;
							
							plane.d = -scene->Vertices[surf->Vertices[0]].Position * scene->Vertices[surf->Vertices[0]].Normal;
							reflectPlane = plane;
							MatrixReflection(mtrans, plane);
							glFrontFace(recurseLevel%2?GL_CCW:GL_CW);
							double planeEq[4];
							planeEq[0] = plane.a; planeEq[1] = plane.b; planeEq[2] = plane.c; planeEq[3] = plane.d;
							
							
							MultiTexture::ActiveTexture(GL_TEXTURE7);
							glDisable(GL_TEXTURE_2D);
							glBindTexture(GL_TEXTURE_2D, 0);
							MultiTexture::ActiveTexture(GL_TEXTURE0);
							bool rdy = reflectionFrameBuffers[recurseLevel]->IsReady();
							reflectionFrameBuffers[recurseLevel]->Bind();
							{
								glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
								
								//int sa = glIsEnabled(GL_CLIP_PLANE0);
								glPushMatrix();
								glMultMatrixf((float*)&mtrans);
								glClipPlane(GL_CLIP_PLANE0+recurseLevel, planeEq);
								glEnable(GL_CLIP_PLANE0+recurseLevel);
								DrawQueue(recurseLevel + 1);
								glPopMatrix();
							}
							reflectionFrameBuffers[recurseLevel]->UnBind();
							MultiTexture::ActiveTexture(GL_TEXTURE7);
							glEnable(GL_TEXTURE_2D);
							glBindTexture(GL_TEXTURE_2D, reflectionTextures[recurseLevel]->GetHandle());
							glFrontFace(recurseLevel%2?GL_CW:GL_CCW);
							glDisable(GL_CLIP_PLANE0+recurseLevel);
							mat->GetProgram()->SetTechnique(Program::ReflectTechnique);
							mat->GetProgram()->Bind();
							mat->Bind((Object *)surf, true);
							mat->GetProgram()->SetUniform(L"reflectTexture", 7);
							curMat = mat;
						}
						else
						{
							if (plane == reflectPlane)
								continue;
							mat->GetProgram()->SetTechnique(Program::NormalTechnique);
							mat->GetProgram()->Bind();
							mat->Bind((Object *)surf, true);
							curMat = mat;
						}
					}
					else if (mat != curMat)
					{
						mat->Bind((Object *)surf, (!curMat || mat->GetProgram() != curMat->GetProgram()));
						curMat = mat;

					}
					if (solution && surf->LightmapID != curLightmapID)
					{
						solution->BindLightmap(surf->LightmapID);
					}
				}
				glDrawElements(GL_POLYGON, surf->VertexCount, GL_UNSIGNED_INT, surf->Vertices);
				/*glBegin(GL_POLYGON);
					for (int z=0; z<surf->VertexCount; z++)
					{
						glNormal3fv((float *)&(scene->Vertices[surf->Vertices[z]].Normal));
						glTexCoord2fv((float *)&(scene->Vertices[surf->Vertices[z]].TexCoord));
						vec2 coord = scene->Vertices[surf->Vertices[z]].LightmapCoord;
						MultiTexture::MultiTexcoord2f(GL_TEXTURE1, coord.x, coord.y);
						glVertex3fv((float *)&(scene->Vertices[surf->Vertices[z]].Position));
					}
				glEnd();*/
			}
		}

		void Renderer::DrawPortal(int id)
		{
			
			if (!scene->BSP[id].IsLeaf())
			{
				return;
			}
			glLineWidth(2.0f);
			glEnable(GL_POLYGON_OFFSET_LINE);
			for (int i=0; i<scene->BSP[id].LeafInfo->Portals.Count(); i++)
			{
				glDisable(GL_CULL_FACE);
				int pid = scene->BSP[id].LeafInfo->Portals[i];
				Portal & ptl = scene->Portals[pid];
				glBegin(GL_POLYGON);
				for (int j=0; j<ptl.Polygon->vertices.Count(); j++)
					glVertex3fv((float *)&(ptl.Polygon->vertices[j]));
				glEnd();
			}
			glDisable(GL_POLYGON_OFFSET_LINE);
		}

		void Renderer::DrawLeaf(int id)
		{
			glLineWidth(1.0f);
			glEnable(GL_POLYGON_OFFSET_LINE);
			glPolygonOffset(-1.0f, 0.0f);
			glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
			if (scene->BSP[id].IsLeaf())
			{
				ConvexHull &hull = scene->BSP[id].LeafInfo->BoundingHull;
				for (int i=0; i<hull.Faces.Count(); i++)
				{
					glBegin(GL_POLYGON);
					for (int j=0; j<hull.Faces[i]->vertices.Count(); j++)
						glVertex3fv((float *)&(hull.Faces[i]->vertices[j]));
					glEnd();
				}
			}
			glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
			glDisable(GL_POLYGON_OFFSET_LINE);
			glLineWidth(1.0f);
		}
	}
}